﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;
using System.Reflection;

//using System.Windows.Forms;

namespace xboxssbeatemup
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        public SpriteBatch spriteBatch;
        public float elapsedGameTime = 0.0f;

        GameObject terrain = new GameObject();
        public HeightMapInfo heightMapInfo;
        int numPlayers = 1;
        public Player[] players;
        
        const int numMissiles = 20;
        GameObject[] missiles;

        AudioEngine audioEngine;
        SoundBank soundBank;
        WaveBank waveBank;
        
        Texture2D pixel;
        CameraComponent camera;
        public Editor editor;

        public Shader shader1 = new Shader("FX\\ShaderTutorial-02");
        public Shader shader2 = new Shader("FX\\ShaderTutorial-05");

        FPSDisplay fpsDisplay;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            this.graphics.PreferredBackBufferWidth = 1024;
            this.graphics.PreferredBackBufferHeight = 768;
            //this.graphics.IsFullScreen = true;

            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            players = new Player[4];
            players[0] = new Player();
            players[1] = new Player();
            players[2] = new Player();
            players[3] = new Player();
            camera = new CameraComponent(this);
            Components.Add(camera);
            editor = new Editor(this, camera, players[0]);
            Components.Add(editor);

            Components.Add(new HUD(this, players));
            shader1.Initialize(this);
            shader2.Initialize(this);

            fpsDisplay = new FPSDisplay(this, "Fonts\\Arial");
            Components.Add(fpsDisplay);

            base.Initialize();
        }

        public SpriteBatch SpriteBatch
        {
            get { return this.spriteBatch; }
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            audioEngine = new AudioEngine("Content\\Sounds\\TutorialAudio.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Sounds\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Sounds\\Sound Bank.xsb");

            terrain.model = Content.Load<Model>("Models\\Terrain\\terrainHeightmap");
            // The terrain processor attached a HeightMapInfo to the terrain model's
            // Tag. We'll save that to a member variable now, and use it to
            // calculate the terrain's heights later.
            heightMapInfo = terrain.model.Tag as HeightMapInfo;
            if (heightMapInfo == null)
            {
                string message = "The terrain model did not have a HeightMapInfo " +
                    "object attached. Are you sure you are using the " +
                    "TerrainProcessor?";
                throw new InvalidOperationException(message);
            }
            terrain.position = Vector3.Zero;// new Vector3(1000.0f, 0.0f, 2000.0f);

            missiles = new GameObject[numMissiles];
            for (int i = 0; i < numMissiles; i++)
            {
                missiles[i] = new GameObject();
                missiles[i].model =
                    Content.Load<Model>("Models\\Weapons\\missile");
            }

            for (int i = 0; i < numPlayers; i++)
            {
                Components.Add(new BPlatformMovement(this, players[i], PlayerIndex.One, BPlatformMovement.Controller.LeftThumb));
                Components.Add(new BPlatformMovement(this, players[i], PlayerIndex.One, BPlatformMovement.Controller.DPad));
                Components.Add(new BPlatformMovement(this, players[i], PlayerIndex.One, BPlatformMovement.Controller.KeyboardArrows));
                //Components.Add(new BPlatformMovement(this, players[i], PlayerIndex.One, BPlatformMovement.Controller.KeyboardNumPad));
                Components.Add(new TBShootProjectile(this, players[i], missiles, Buttons.X));
                Components.Add(new TBShootProjectile(this, players[i], missiles, Keys.X));
                players[i].model = Content.Load<Model>("Models\\Characters\\Tutorial_08");
                players[i].modelRotation = new Vector3(0.0f, 0.0f, MathHelper.Pi);
                players[i].modelPosition = new Vector3(0.0f, 15.0f, 0.0f);
                players[i].scale = 1.0f;
            }

            //Components.Add(new CBFollowHorizontally(this, camera, players[0]));

            pixel = Content.Load<Texture2D>("Images\\Pixel");

        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

#if !XBOX
            KeyboardState keyboardState = Keyboard.GetState();
            if (keyboardState.IsKeyDown(Keys.Escape))
                this.Exit();
#endif

            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            audioEngine.Update();

            // Make player follow terrain
            players[0].position.Y = heightMapInfo.GetHeight(players[0].position) + 1.0f;

            elapsedGameTime += (float)gameTime.ElapsedGameTime.Milliseconds / 1000;

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(new Color(new Vector3(0.15f)));

            DrawTerrain(terrain);
            shader1.DrawGameObject(this, camera, players[0]);
            shader2.DrawGameObject(this, camera, players[0]);
            //DrawGameObject(players[0]);

            foreach (GameObject missile in missiles)
            {
                if (missile.alive)
                {
                    DrawGameObject(missile);
                }
            }

            base.Draw(gameTime);
        }

        void DrawGameObject(GameObject gameObject)
        {
            foreach (ModelMesh mesh in gameObject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    //effect.DiffuseColor = Color.White.ToVector3();
                    effect.AmbientLightColor = Color.White.ToVector3();
                    //effect.SpecularColor = Color.White.ToVector3();

                    effect.World =
                        Matrix.CreateFromYawPitchRoll(
                        gameObject.modelRotation.Y,
                        gameObject.modelRotation.X,
                        gameObject.modelRotation.Z) *
                        Matrix.CreateTranslation(gameObject.modelPosition) *
                        Matrix.CreateFromYawPitchRoll(
                        gameObject.rotation.Y,
                        gameObject.rotation.X,
                        gameObject.rotation.Z) *
                        Matrix.CreateScale(gameObject.scale) *
                        Matrix.CreateTranslation(gameObject.position);
                    effect.Projection = camera.Projection;
                    effect.View = camera.View;
                }
                mesh.Draw();
            }
        }

        void DrawTerrain(GameObject gameObject)
        {
            foreach (ModelMesh mesh in terrain.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World =
                        Matrix.CreateFromYawPitchRoll(
                        gameObject.rotation.Y,
                        gameObject.rotation.X,
                        gameObject.rotation.Z) *
                        Matrix.CreateScale(gameObject.scale) *
                        Matrix.CreateTranslation(gameObject.position);
                    effect.Projection = camera.Projection;
                    effect.View = camera.View;

                    effect.EnableDefaultLighting();

                    // Set the specular lighting to match the sky color.
                    effect.SpecularColor = new Vector3(0.15f);// new Vector3(0.6f, 0.4f, 0.2f);
                    effect.SpecularPower = 8;

                    // Set the fog to match the distant mountains
                    // that are drawn into the sky texture.
                    effect.FogEnabled = true;
                    effect.FogColor = new Vector3(0.15f);
                    effect.FogStart = 200;
                    effect.FogEnd = 620;
                }

                mesh.Draw();
            }
        }

    }
}
